package com.cby.library.tool.crash;

import android.app.Application;
import android.content.Context;

import androidx.annotation.NonNull;


import com.cby.library.tool.crash.record.ICrashProcessor;
import com.cby.library.tool.crash.record.LocalCrashProcessor;
import com.cby.library.tool.util.LogUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * Description:CrashManager
 *
 * @author 陈宝阳
 * @create 2020/11/17 16:03
 */
public class CrashManager implements Thread.UncaughtExceptionHandler {

    private static final String TAG = CrashManager.class.getSimpleName();

    private List<ICrashProcessor> iCrashProcessorList = new ArrayList<>();

    private static CrashManager sInstance;

    private Context context;

    private CrashListener listener;

    private Thread.UncaughtExceptionHandler defaultHandler;

    private CrashManager() {
    }

    public static CrashManager getInstance() {
        if (sInstance == null) {
            synchronized (CrashManager.class) {
                if (sInstance == null) {
                    sInstance = new CrashManager();
                }
            }
        }
        return sInstance;
    }

    public void init(Application application, CrashListener listener) {
        LifecycleCallback.getInstance().init(application);
        this.context = application;
        this.listener = listener;
        //获取系统默认的UncaughtExceptionHandler
        defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
        //将当前实例设为系统默认的异常处理器
        //设置一个处理者当一个线程突然因为一个未捕获的异常而终止时将自动被调用。
        //未捕获的异常处理的控制第一个被当前线程处理，如果该线程没有捕获并处理该异常，其将被线程的ThreadGroup对象处理，最后被默认的未捕获异常处理器处理。
        Thread.setDefaultUncaughtExceptionHandler(this);
    }

    public void setCrashLocal(){
        addCrashProcessor(new LocalCrashProcessor());
    }

    public void addCrashProcessor(ICrashProcessor processor) {
        if (processor != null) {
            iCrashProcessorList.add(processor);
        }
    }

    @Override
    public void uncaughtException(@NonNull Thread thread, @NonNull Throwable throwable) {
        boolean isHandle = handleException(throwable);
        initCustomBug(throwable);
        if (defaultHandler != null && !isHandle) {
            //收集完信息后，交给系统自己处理崩溃
            //uncaughtException (Thread t, Throwable e) 是一个抽象方法
            //当给定的线程因为发生了未捕获的异常而导致终止时将通过该方法将线程对象和异常对象传递进来。
            defaultHandler.uncaughtException(thread, throwable);
        } else {
            //否则自己处理
            if (context instanceof Application) {
                LogUtils.i(TAG, "handleException--- ex----重启activity-");
                if (listener != null) {
                    listener.againStartApp();
                }
            }
        }
        /*if (isFinishActivity){
            CrashHelper.getInstance().setSafe(thread,ex);
        }*/
    }

    /**
     * 初始化bug
     *
     * @param ex
     */
    private void initCustomBug(Throwable ex) {
        //自定义上传crash，支持开发者上传自己捕获的crash数据
        //StatService.recordException(mContext, ex);
        if (listener != null) {
            //捕获监听中异常，防止外部开发者使用方代码抛出异常时导致的反复调用
            try {
                listener.recordException(ex);
            } catch (Throwable e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 自定义错误处理,收集错误信息
     * 发送错误报告等操作均在此完成.
     * 开发者可以根据自己的情况来自定义异常处理逻辑
     */
    private boolean handleException(Throwable ex) {
        if (ex == null) {
            LogUtils.i(TAG, "handleException--- ex==null");
            return false;
        }
        //收集crash信息
        String msg = ex.getLocalizedMessage();
        if (msg == null) {
            return false;
        }
        LogUtils.i(TAG, "handleException--- ex-----" + msg);
        ex.printStackTrace();
        //执行奔溃处理者
        executeCrashProcessor(ex);
        return true;
    }

    private void executeCrashProcessor(Throwable ex) {
        if (iCrashProcessorList.isEmpty()) {
            return;
        }
        int size = iCrashProcessorList.size();
        for (int i = 0; i < size; i++) {
            iCrashProcessorList.get(i).dealCrashInfo(context, ex);
        }
    }

}
